/*
 * Copyrignt (c) xuzeshui.com. All Rights Reserved.
 * Author: Xiaobao Zeng<zengxiaobao@skyworth.com>
 * Created Time: 2017-07-10 10:12:05
 * Last Modified: 2017-07-11 11:54:03
 * File Name: v1-2.go
 * Description:
 */

package statis

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"sort"
	"strconv"
	"strings"
	"time"

	"qkleague/rpc/client/qingke"
	rpc "qkleague/rpc/client/qkstatis"

	log "github.com/cihub/seelog"
)

/*
   qtype-请求类型：
1-昨日数据
2-当日数据
3-总数据
4-洗衣点数据
5-洗衣机数据
*/

func (p *QKleagueStatis) GetQKLStatis(qtype int, userId string, extra map[string]interface{}) (error, []*StatisResp) {
	var resp []*StatisResp
	var err error
	switch qtype {
	case 1:
		fallthrough
	case 2:
		fallthrough
	case 3:
		err, resp = p.CombLeagueStatis(qtype, userId, extra)
	case 4:
		err, resp = p.CombWashRoomStatis(qtype, userId, extra)
	case 5:
		err, resp = p.CombWasherStatis(qtype, extra)
	default:
	}
	return err, resp
}

func (p *QKleagueStatis) CombLeagueStatis(qtype int, leagueId string, extra map[string]interface{}) (error, []*StatisResp) {
	return p.leagueStatisAll(qtype, leagueId)
}

func (p *QKleagueStatis) CombWashRoomStatis(qtype int, leagueId string, extra map[string]interface{}) (error, []*StatisResp) {
	ok, timeType, timeRange := p.isValidBodyParam(qtype, extra)
	if !ok {
		return errors.New("body参数缺失"), nil
	}
	if !p.isValidTimeRange(timeType, timeRange) {
		return errors.New("body参数错误"), nil
	}
	resp := make([]*StatisResp, 0)

	extraRooms := make([]string, 0)
	allRooms := false
	if val, ok := extra["rooms"]; ok {
		tmp := val.([]interface{})
		for _, dt := range tmp {
			extraRooms = append(extraRooms, dt.(string))
		}
	} else {
		allRooms = true
		//需要获取加盟商所有的洗衣点信息
	}

	if !allRooms { //客户端上传洗衣点参数
		resp = p.WashRoomStatisSome(extraRooms, leagueId, timeRange)
	} else {
		resp = p.WashRoomStatisAll(leagueId, timeRange)
	}
	return nil, resp
}

func (p *QKleagueStatis) CombWasherStatis(qtype int, extra map[string]interface{}) (error, []*StatisResp) {
	ok, timeType, timeRange := p.isValidBodyParam(qtype, extra)
	if !ok {
		return errors.New("body参数错误"), nil
	}
	if !p.isValidTimeRange(timeType, timeRange) {
		return errors.New("body参数错误"), nil
	}
	resp := make([]*StatisResp, 0)

	washRoomId := ""
	extraWashers := make([]string, 0)
	allWashers := false
	if val, ok := extra["washers"]; ok {
		tmp := val.([]interface{})
		for _, dt := range tmp {
			extraWashers = append(extraWashers, dt.(string))
		}
	} else {
		allWashers = true
		if val, ok := extra["rooms"]; ok {
			tmp := val.([]interface{})
			if len(tmp) == 1 {
				washRoomId = tmp[0].(string)
			} else {
				return errors.New("body参数错误, 洗衣点标识缺失"), nil
			}
		}
		//需要获取洗衣点所有的洗衣机信息
	}
	if !allWashers { //客户端上传洗衣点参数
		resp = p.washerStatisSome(extraWashers, "", timeRange)
	} else {
		resp = p.washerStatisAll(washRoomId, timeRange)
	}
	return nil, resp
}

func (p *QKleagueStatis) leagueStatisAll(qtype int, leagueId string) (error, []*StatisResp) {
	resp := make([]*StatisResp, 0, 1)
	err, data := p.getLeagueProfit(qtype, leagueId, "")
	if err == nil {
		//加盟商某日的数据
		if len(data) == 1 {
			resp = append(resp, &StatisResp{data[0], make([]*StatisItem, 0, 0)})
			return nil, resp
		} else if len(data) == 0 {
			resp = append(resp, &StatisResp{&StatisItem{}, make([]*StatisItem, 0, 0)})
			return nil, resp
		}

		//加盟商的总数据
		sum := &StatisItem{}
		for _, dt := range data {
			sum.TotalOrder += dt.TotalOrder
			sum.pay += dt.pay
			sum.revenue += dt.revenue
			sum.WashedNum += dt.WashedNum
			sum.washerNum += dt.washerNum

			sum.ActualPay = fmt.Sprintf("%.2f", float64(sum.pay)/float64(100))
			sum.TotalRevenue = fmt.Sprintf("%.2f", float64(sum.revenue))
			if sum.washerNum != 0 {
				sum.O1Machine = fmt.Sprintf("%.2f", float64(sum.TotalOrder)/float64(sum.washerNum))
				sum.P1Machine = fmt.Sprintf("%.2f", float64(sum.revenue)/float64(sum.washerNum)/float64(100))
			} else {
				sum.O1Machine = "0.00"
				sum.P1Machine = "0.00"
			}
			if sum.TotalOrder != 0 {
				sum.P1Order = fmt.Sprintf("%.2f", float64(sum.revenue)/float64(sum.TotalOrder)/float64(100))
			} else {
				sum.P1Order = "0.00"
			}
		}
		resp = append(resp, &StatisResp{sum, make([]*StatisItem, 0, 0)})
		return nil, resp
	}
	return err, nil
}

func (p *QKleagueStatis) WashRoomStatisSome(extraRooms []string, leagueId, timeRange string) []*StatisResp {
	resp := make([]*StatisResp, 0)
	//记录从统计系统获取的统计数据 数据格式 washRoomId-[]（date）
	roomStatis := make(map[string][]*StatisItem)
	for _, washRoomId := range extraRooms {
		err, data := p.getWashRoomProfit(leagueId, washRoomId, timeRange)
		if err != nil {
			log.Errorf("QKleagueStatis WashRoomStatisSome err. 获取洗衣点统计数据失败. err:%s, washRoomId:%s, leagueId:%s, timeRange:%s", err.Error(), washRoomId, leagueId, timeRange)
			continue
		}
		roomStatis[washRoomId] = data
	}
	//转换展示维度 数据格式 date-[]（washRoomId）
	dates := make([]string, 0)
	all := make(map[string][]*StatisItem, 0)
	for _, data := range roomStatis {
		for _, dt := range data {
			if _, ok := all[dt.Date]; !ok {
				dates = append(dates, dt.Date)
				all[dt.Date] = make([]*StatisItem, 0)
			}
			all[dt.Date] = append(all[dt.Date], dt)
		}
	}

	//将dates按照时间由近到远排序
	sort.Sort(sort.Reverse(sort.StringSlice(dates)))

	for _, date := range dates {
		val := all[date]
		sum := &StatisItem{}
		parts := make([]*StatisItem, 0, len(all))
		sum.Date = date
		for _, dt := range val {
			sum.TotalOrder += dt.TotalOrder
			sum.pay += dt.pay
			sum.revenue += dt.revenue
			sum.WashedNum += dt.WashedNum
			sum.washerNum += dt.washerNum

			//补充洗衣点的名称 query/ByRoomId/batch
			if data := qingke.GetWashRoomInfoByRoomId(dt.StatisId); data != nil {
				ri := data.([]interface{})[0].(map[string]interface{})
				dt.StatisTDesc = ri["room_name"].(string)
			}

			parts = append(parts, dt)
		}
		sum.ActualPay = fmt.Sprintf("%.2f", float64(sum.pay)/float64(100))
		sum.TotalRevenue = fmt.Sprintf("%.2f", float64(sum.revenue)/float64(100))
		if sum.washerNum != 0 {
			sum.O1Machine = fmt.Sprintf("%.2f", float64(sum.TotalOrder)/float64(sum.washerNum))
			sum.P1Machine = fmt.Sprintf("%.2f", float64(sum.revenue)/float64(sum.washerNum)/float64(100))
		} else {
			sum.O1Machine = "0.00"
			sum.P1Machine = "0.00"
		}
		if sum.TotalOrder != 0 {
			sum.P1Order = fmt.Sprintf("%.2f", float64(sum.revenue)/float64(sum.TotalOrder)/float64(100))
		} else {
			sum.P1Order = "0.00"
		}

		resp = append(resp, &StatisResp{sum, parts})
	}
	return resp
}

//获取加盟商所有的洗衣点的数据， 参数rooms为空
func (p *QKleagueStatis) WashRoomStatisAll(leagueId, timeRange string) []*StatisResp {
	resp := make([]*StatisResp, 0)
	data := qingke.GetRoomIds(leagueId)
	if data == nil {
		return resp
	}

	roomIds := make([]string, 0)
	ris := data.([]interface{})
	for _, val := range ris {
		roomIds = append(roomIds, val.(string))
	}
	return p.WashRoomStatisSome(roomIds, leagueId, timeRange)
}

//2中查看方式
//1: 查看洗衣点中洗衣机的统计数据（某日或者某月）
//2： 查看某一天洗衣机的某一时间段的数据
func (p *QKleagueStatis) washerStatisSome(extraWashers []string, washRoomId, timeRange string) []*StatisResp {
	resp := make([]*StatisResp, 0)
	washerStatis := make([][]*StatisItem, 0)
	for _, washerId := range extraWashers {
		err, data := p.getWasherProfit(washerId, timeRange)
		if err != nil {
			log.Errorf("QKleagueStatis washerStatisSome err. 获取洗衣机统计数据失败. err:%s, washerId:%s, timeRange:%s", err.Error(), washerId, timeRange)
			continue
		}
		washerStatis = append(washerStatis, data)
	}

	if len(washerStatis) == 0 {
		return resp
	}

	if washRoomId == "" { //1
		sum := &StatisItem{}
		data := washerStatis[0]
		parts := make([]*StatisItem, 0, len(data))
		for _, dt := range data {
			sum.TotalOrder += dt.TotalOrder
			sum.pay += dt.pay
			sum.revenue += dt.revenue
			sum.WashedNum += dt.WashedNum
			sum.washerNum += dt.washerNum

			parts = append(parts, dt)
		}

		sum.ActualPay = fmt.Sprintf("%.2f", float64(sum.pay)/float64(100))
		sum.TotalRevenue = fmt.Sprintf("%.2f", float64(sum.revenue)/float64(100))
		if sum.washerNum != 0 {
			sum.O1Machine = fmt.Sprintf("%.2f", float64(sum.TotalOrder)/float64(sum.washerNum))
			sum.P1Machine = fmt.Sprintf("%.2f", float64(sum.revenue)/float64(sum.washerNum)/float64(100))
		} else {
			sum.O1Machine = "0.00"
			sum.P1Machine = "0.00"
		}
		if sum.TotalOrder != 0 {
			sum.P1Order = fmt.Sprintf("%.2f", float64(sum.revenue)/float64(sum.TotalOrder)/float64(100))
		} else {
			sum.P1Order = "0.00"
		}

		resp = append(resp, &StatisResp{sum, parts})
	} else {
		sum := &StatisItem{}
		parts := make([]*StatisItem, 0, len(washerStatis))
		for _, dt := range washerStatis {
			if len(dt) == 0 {
				continue
			}
			sum.TotalOrder += dt[0].TotalOrder
			sum.pay += dt[0].pay
			sum.revenue += dt[0].revenue
			sum.WashedNum += dt[0].WashedNum
			sum.washerNum += dt[0].washerNum

			parts = append(parts, dt[0])
		}
		sum.ActualPay = fmt.Sprintf("%.2f", float64(sum.pay)/float64(100))
		sum.TotalRevenue = fmt.Sprintf("%.2f", float64(sum.revenue)/float64(100))
		sum.O1Machine = "0.00"
		sum.P1Machine = "0.00"
		if sum.TotalOrder != 0 {
			sum.P1Order = fmt.Sprintf("%.2f", float64(sum.revenue)/float64(sum.TotalOrder)/float64(100))
		} else {
			sum.P1Order = "0.00"
		}
		resp = append(resp, &StatisResp{sum, parts})
	}
	return resp
}

func (p *QKleagueStatis) washerStatisAll(washRoomId, timeRange string) []*StatisResp {
	ok, data := qingke.NewQueryWahserInfoByRoomid("", washRoomId)
	if ok {
		ws := data.([]interface{})
		washers := make([]string, 0, len(ws))
		for _, dt := range ws {
			washers = append(washers, dt.(map[string]interface{})["washerid"].(string))
		}
		return p.washerStatisSome(washers, washRoomId, timeRange)
	}
	log.Errorf("QKleagueStatis washerStatisAll err. 获取洗衣点内的洗衣机信息失败. washRoomId:%s", washRoomId)
	return nil
}

//获取特定加盟商的营收数据
func (p *QKleagueStatis) getLeagueProfit(qtype int, leagueId, timePeriod string) (error, []*StatisItem) {
	resp := make([]*StatisItem, 0)
	timeRange := ""
	if qtype == 1 {
		yesterday := time.Now().AddDate(0, 0, -1).Format("2006-01-02")
		timeRange = yesterday + "~" + yesterday
	} else if qtype == 2 {
		now := time.Now().Format("2006-01-02")
		timeRange = now + "~" + now
	} else if 3 == qtype {
		now := time.Now().Format("2006-01")
		timeRange = "2016-12" + "~" + now
	}

	//用户在查看洗衣点数据时， 没有选择特定洗衣点-默认所有洗衣点
	if qtype == 4 && timePeriod != "" {
		timeRange = timePeriod
	}
	//获取加盟商的某日或者某个时间段的营收
	ok, lDatas := rpc.LeagueProfitList(leagueId, timeRange)
	if ok {
		if lDatas != nil {
			data := make([]*LeagueProfit, 0)
			if b, err := json.Marshal(lDatas); err == nil {
				if err = json.Unmarshal(b, &data); err == nil {
					for _, dt := range data {
						si := &StatisItem{}
						si.Date = dataFlagTransfer(dt.DateFlag)
						si.StatisId = dt.LeagueId
						si.StatisTDesc = dt.LeagueName
						si.TotalOrder = dt.WashingOrder
						si.ActualPay = dt.WashingProfit
						revenue,_:=strconv.ParseFloat(dt.WashingTotal,64)
						si.revenue = int(revenue)
						si.pay = str2int(dt.WashingProfit)
						si.TotalRevenue = fmt.Sprintf("%.2f", float64(revenue))
						si.P1Machine = dt.Sp1m
						si.O1Machine = dt.So1m
						if si.TotalOrder == 0 {
							si.P1Order = "0.00"
						} else {
							si.P1Order = fmt.Sprintf("%.2f", float64(revenue)/float64(si.TotalOrder)/float64(100))
						}
						si.WashedNum = dt.WashingPeer
						resp = append(resp, si)
					}
				} else {
					log.Errorf("QKleagueStatis getLeagueProfit json err. err:%s", err.Error())
					return errors.New("json格式化失败"), nil
				}
			} else {
				log.Errorf("QKleagueStatis getLeagueProfit json err. err:%s", err.Error())
				return errors.New("json格式化失败"), nil
			}
		} else {
			return nil, make([]*StatisItem, 0, 0)
		}
	} else {
		return errors.New("查询数据失败"), nil
	}
	return nil, resp
}

//获取特定洗衣点的营收数据
func (p *QKleagueStatis) getWashRoomProfit(leagueId, washRoomId, timeRange string) (error, []*StatisItem) {
	resp := make([]*StatisItem, 0)
	//获取洗衣点某个时间段的营收
	ok, lDatas := rpc.WashRoomProfitList(leagueId, washRoomId, timeRange)
	data := make([]*WashRoomProfit, 0)
	if ok {
		if lDatas != nil {
			if b, err := json.Marshal(lDatas); err == nil {
				if err = json.Unmarshal(b, &data); err == nil {
					for _, dt := range data {
						si := &StatisItem{}
						si.Date = dataFlagTransfer(dt.DateFlag)
						si.StatisId = dt.WashRoomId
						si.TotalOrder = dt.WashingOrder
						si.ActualPay = dt.WashingProfit
						revenue,_:=strconv.ParseFloat(dt.WashingTotal,64)
						si.revenue = int(revenue)
						si.pay = str2int(dt.WashingProfit)
						si.TotalRevenue = fmt.Sprintf("%.2f", float64(revenue)/float64(100))
						si.P1Machine = dt.Sp1m
						si.O1Machine = dt.So1m
						if si.TotalOrder == 0 {
							si.P1Order = "0.00"
						} else {
							si.P1Order = fmt.Sprintf("%.2f", float64(revenue)/float64(si.TotalOrder)/float64(100))
						}
						si.WashedNum = dt.WashingPeer
						si.washerNum = dt.WasherNumActive
						resp = append(resp, si)
					}
				} else {
					log.Errorf("QKleagueStatis getWashRoomProfit json err. err:%s", err.Error())
					return errors.New("json格式化失败"), nil
				}
			} else {
				log.Errorf("QKleagueStatis getWashRoomProfit json err. err:%s", err.Error())
				return errors.New("json格式化失败"), nil
			}
		} else {
			return nil, make([]*StatisItem, 0, 0)
		}
	} else {
		return errors.New("查询数据失败"), nil
	}
	return nil, resp
}

//获取特定洗衣机的营收数据
func (p *QKleagueStatis) getWasherProfit(washerId, timeRange string) (error, []*StatisItem) {
	resp := make([]*StatisItem, 0)
	//获取洗衣机的某日或者某个时间段的营收
	ok, lDatas := rpc.WasherProfitList(washerId, timeRange)
	if ok {
		if lDatas != nil {
			data := make([]*WasherProfit, 0)
			if b, err := json.Marshal(lDatas); err == nil {
				if err = json.Unmarshal(b, &data); err == nil {
					for _, dt := range data {
						si := &StatisItem{}
						si.Date = dataFlagTransfer(dt.DateFlag)
						si.StatisId = dt.WasherId
						si.StatisTDesc = dt.WasherId
						si.TotalOrder = dt.WashingOrder
						si.ActualPay = dt.WashingProfit
						si.pay = str2int(dt.WashingProfit)
						si.revenue = dt.WashingTotal
						si.TotalRevenue = fmt.Sprintf("%.2f", float64(dt.WashingTotal)/float64(100))
						if si.TotalOrder != 0 {
							si.P1Order = fmt.Sprintf("%.2f", float64(si.pay)/float64(si.TotalOrder))
						} else {
							si.P1Order = "0.00"
						}
						si.WashedNum = dt.WashingPeer
						resp = append(resp, si)
					}
					return nil, resp
				} else {
					log.Errorf("QKleagueStatis getWasherProfit json err. err:%s", err.Error())
					return errors.New("json格式化失败"), nil
				}
			} else {
				log.Errorf("QKleagueStatis getWasherProfit json err. err:%s", err.Error())
				return errors.New("json格式化失败"), nil
			}
		} else {
			return errors.New("查询数据失败"), nil
		}
	} else {
		return errors.New("查询数据失败"), nil
	}
	return nil, resp
}

//判断body参数是否合法
func (p *QKleagueStatis) isValidBodyParam(qtype int, extra map[string]interface{}) (bool, int, string) {
	timeType := 0
	timeRange := ""

	//加盟商粒度
	switch qtype {
	case 1:
		yesterday := time.Now().AddDate(0, 0, -1).Format("2006-01-02")
		return true, 1, yesterday + "~" + yesterday
	case 2:
		now := time.Now().Format("2006-01-02")
		return true, 1, now + "~" + now
	case 3:
		now := time.Now().Format("2006-01-02")
		return true, 1, "2016-12-22" + "~" + now
	}

	//洗衣点和洗衣机粒度
	if extra == nil {
		return false, timeType, timeRange
	}

	if val, ok := extra["time_type"]; ok {
		timeType = int(val.(float64))
	}
	if val, ok := extra["time_range"]; ok {
		timeRange = val.(string)
	}
	if timeType == 0 || timeRange == "" {
		return false, timeType, timeRange
	}
	return true, timeType, timeRange
}

//判断body时间范围参数是否正确
func (p *QKleagueStatis) isValidTimeRange(timeType int, timeRange string) bool {
	timeRange = strings.Replace(timeRange, " ", "", -1)

	//结束时间必须大于开始时间
	tra := strings.Split(timeRange, "~")
	if len(tra) != 2 || tra[1] < tra[0] {
		return false
	}
	switch timeType {
	case 1:
		return 21 == len(timeRange)
	case 2:
		return 15 == len(timeRange)
	case 3:
		return 9 == len(timeRange)
	default:
		return false
	}
	return false
}

// //获取一个时间段内的每个分片时间，时间日期从近到远排序
// func (p *QKleagueStatis) calPeriodsByTstr(timeType int, timeRange string) []string {
//         timeArray := strings.Split(timeRange, "~")
//         if len(timeArray) != 2 {
//                 return make([]string, 0, 0)
//         }
//         start := timeArray[0]
//         end := timeArray[1]
//         data := make([]string, 0)
//         for tmp := start; tmp <= end; {
//                 data = append(data, tmp)
//                 if 1 == timeType {
//                         tm, _ := time.ParseInLocation("2006-01-02", tmp, time.Local)
//                         tm = tm.AddDate(0, 0, 1)
//                         tmp = tm.Format("2006-01-02")
//                 } else if 3 == timeType {
//                         tm, _ := time.ParseInLocation("2006-01", tmp, time.Local)
//                         tm = tm.AddDate(0, 1, 0)
//                         tmp = tm.Format("2006-01")
//                 }
//         }
//         sort.Sort(sort.Reverse(sort.StringSlice(data)))
//         return data
// }

//元 -> 分
func str2int(str string) int {
	if str == "" {
		return 0
	}
	sum := 0 //分
	arrays := strings.Split(str, ".")
	if len(arrays) == 2 {
		intPart, _ := strconv.Atoi(arrays[0])
		sum += 100 * intPart

		pointPart, _ := strconv.Atoi(arrays[1])
		sum += 100 * pointPart / int(math.Pow(float64(10), float64(len(arrays[1]))))
		return sum
	}

	return sum * 100
}

//日期格式转化
func dataFlagTransfer(date string) string {
	resp := ""
	dateByte := []byte(date)
	length := len(dateByte)
	if length >= 4 {
		resp = "20" + string(dateByte[:2]) + "-" + string(dateByte[2:4])
		if length == 4 { //月
			return resp
		} else { //日
			resp = resp + "-" + string(dateByte[4:6])
			return resp
		}
	}
	return resp
}
